package org.example.brave.servlet;

import brave.Span;
import brave.internal.Nullable;
import org.example.brave.http.HttpServerRequest;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;

/**
 * Besides delegating to {@link HttpServletRequest} methods, this also parses the remote IP of the
 * client.
 *
 * @since 5.10
 */
// Public for use in sparkjava or other frameworks that re-use servlet types
public final class HttpServletRequestWrapper extends HttpServerRequest {
    /** @since 5.10 */
    public static HttpServerRequest create(HttpServletRequest request) {
        return new HttpServletRequestWrapper(request);
    }

    final HttpServletRequest delegate;

    HttpServletRequestWrapper(HttpServletRequest delegate) {
        if (delegate == null) throw new NullPointerException("delegate == null");
        this.delegate = delegate;
    }

    @Override public final Object unwrap() {
        return delegate;
    }

    /**
     * This sets the client IP:port to the {@linkplain HttpServletRequest#getRemoteAddr() remote
     * address} if the {@link #parseClientIpFromXForwardedFor default parsing} fails.
     */
    @Override public boolean parseClientIpAndPort(Span span) {
        if (parseClientIpFromXForwardedFor(span)) return true;
        return span.remoteIpAndPort(delegate.getRemoteAddr(), delegate.getRemotePort());
    }

    @Override public final String method() {
        return delegate.getMethod();
    }

    @Override public String route() {
        Object maybeRoute = delegate.getAttribute("http.route");
        return maybeRoute instanceof String ? (String) maybeRoute : null;
    }

    @Override public final String path() {
        return delegate.getRequestURI();
    }

    // not final as some implementations may be able to do this more efficiently
    @Override public String url() {
        StringBuffer url = delegate.getRequestURL();
        if (delegate.getQueryString() != null && !delegate.getQueryString().isEmpty()) {
            url.append('?').append(delegate.getQueryString());
        }
        return url.toString();
    }

    @Override public final String header(String name) {
        return delegate.getHeader(name);
    }

    /** Looks for a valid request attribute "error" */
    @Nullable
    Throwable maybeError() {
        Object maybeError = delegate.getAttribute("error");
        if (maybeError instanceof Throwable) return (Throwable) maybeError;
        maybeError = delegate.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
        if (maybeError instanceof Throwable) return (Throwable) maybeError;
        return null;
    }
}
